﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using TC.WEB.Site.Core.Model;
using TC.WEB.Site.Core;
using TC.WEB.Site.Models;
using System.Text;
using TC.WEB.Site.Models.DTO;

namespace TC.SSO.Server.Filters
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class RequestTokenFilter : ActionFilterAttribute
    {
        /// <summary>
        /// datetime转换为unixtime
        /// </summary>
        /// <param name="time"></param>
        /// <returns></returns>
        public static int ConvertDateTimeInt(System.DateTime time)
        {
            System.DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new System.DateTime(1970, 1, 1));
            return (int)(time - startTime).TotalSeconds;
        }

        /// <summary>
        /// 计算签名
        /// </summary>
        /// <param name="appid"></param>
        /// <param name="appkey"></param>
        /// <param name="timestamp"></param>
        /// <returns></returns>
        public static string Signature(string appid,string appkey, int timestamp)
        {
            using (var _sha1 = System.Security.Cryptography.SHA1.Create())
            {
                var paras = new string[] { appid, appkey, timestamp.ToString() };
                Array.Sort(paras);
                byte[] buffer = Encoding.UTF8.GetBytes(string.Join("", paras));

                byte[] result = _sha1.ComputeHash(buffer);
                return BitConverter.ToString(result).Replace("-", "").ToUpper();
            }
        }

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var rq = filterContext.HttpContext.Request;
            string appid = (rq["appid"] ?? "").Trim(),
                   sign = (rq["sign"] ?? "").Trim();
            int timestamp = 0;
            int.TryParse((rq["timestamp"] ?? "").Trim(), out timestamp);

            string message = string.Empty;

            int code = Check(appid, sign, timestamp, out message);

            if (code != 200)
            {
                JsonResult result = new JsonResult();
                result.Data = new OperRult { Success = false, Message = message };
                result.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
                filterContext.Result = result;
                return;
            }
            //记录日志
            ApplicationReqLog log = new ApplicationReqLog();
            log.AppID = int.Parse(appid);
            log.Code = code;
            log.Timestamp = timestamp;
            log.Sign = sign;
            log.URL = filterContext.HttpContext.Request.Url.ToString();
            System.Threading.ThreadPool.QueueUserWorkItem(obj => {
                try
                {
                    var l = obj as ApplicationReqLog;
                    var m = BaseModel.M<ApplicationReqLogModel>();
                    var r = m.Add(l);
                }
                catch (Exception ex)
                {
                }
            },log);
        }

        internal static int Check(string appid, string sign, int timestamp, out string message)
        {
            int serverTimestamp = ConvertDateTimeInt(DateTime.Now);
            if (string.IsNullOrEmpty(appid) || timestamp == 0 || string.IsNullOrEmpty(sign))
            {
                message = "appid、timestamp、sign不能为空！";
                return 400;
            }

            if (Math.Abs(timestamp - serverTimestamp) > 1 * 60)
            {
                message = "非法的时间戳！";
                return 400;
            }

            var reqM = BaseModel.M<ApplicationReqLogModel>();
            var reqRult = reqM.Get(timestamp);
            if (reqRult.Success)
            {
                //message = "请求已过期！";
                //return 400;
            }

            var appM = BaseModel.M<ApplicationModel>();
            var appRult = appM.GetApp(appid);
            if (!appRult.Success)
            {
                message = appRult.Message;
                return 401;
            }

            string realSign = Signature(appid, appRult.Value.AppKey, timestamp);
            if (realSign != sign)
            {
                //message = "签名不正确";
                //return 403;
            }

            message = string.Empty;
            return 200;
        }

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            base.OnActionExecuted(filterContext);
        }
    }

    [AttributeUsage(AttributeTargets.Class|AttributeTargets.Method)]
    public class RequestExceptionTokenFilter :FilterAttribute, IExceptionFilter
    {
        /// <summary>
        /// 正式发布时请将此值改为false
        /// </summary>
        const bool DEBUG = true;
        public void OnException(ExceptionContext filterContext)
        {
            OperRult rult = new OperRult { Success = false, Message = "服务器内部错误！" };
            if (DEBUG)
            {
                rult.Message = filterContext.Exception.Message;
            }

            Ocor.Logger.LogWriter.Write(filterContext.Exception, "RequestExceptionTokenFilter");
            var jsonRult = new JsonResult();
            jsonRult.Data = rult;
            jsonRult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
            filterContext.Result = jsonRult;
            filterContext.ExceptionHandled = true;
        }
    }

}